package com.xcdh.ittools.service.impl;

import com.alibaba.druid.pool.DruidDataSource;
import com.api.ittools.entity.*;
import com.api.ittools.query.DbQuery;
import com.api.ittools.vo.ElTreeVo;
import com.api.ittools.vo.ToolDatasourceVo;
import com.baomidou.dynamic.datasource.annotation.Slave;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xcdh.commons.utils.EncryptUtil;
import com.xcdh.domain.RequestPage;
import com.xcdh.ittools.mapper.ToolDatasourceMapper;
import com.xcdh.ittools.mapping.ParamKV;
import com.xcdh.ittools.service.ToolDatasourceService;
import com.xcdh.ittools.sql.DSql;
import com.xcdh.ittools.type.ITToolReturnType;
import com.xcdh.ittools.utils.DataSourceChange;
import com.xcdh.ittools.utils.MysqlDbUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slave
public class ToolDatasourceServiceImpl extends ServiceImpl<ToolDatasourceMapper , ToolDatasource> implements ToolDatasourceService {
    @Autowired
    private ToolDatasourceMapper toolDatasourceMapper ;

    @Override
    public boolean save(ToolDatasource ds){
        if(!StringUtils.isBlank(ds.getPassword())){
            String password = ds.getPassword();
            String codePad = EncryptUtil.getInstance().DESencode(password, ds.getUsername());
            ds.setPassword(codePad);
        }
        return super.save(ds) ;
    }

    @Override
    public boolean saveOrUpdate(ToolDatasource entity) {
        if(entity.getDsId() != null){
            entity.setPassword(null);
        }
        return super.saveOrUpdate(entity);
    }

    @Override
    public List<ElTreeVo> queryDbs(ToolDatasource datasource) {
        return null;
    }

    public ToolDatasource getDsById(DbQuery query){
        ToolDatasource ds = toolDatasourceMapper.selectById(query.getDsId());
        String password = ds.getPassword();
        String decodePwd = EncryptUtil.getInstance().DESdecode(password, ds.getUsername());
        ds.setPassword(decodePwd);
        return ds ;
    }

    @Override
    public List<ElTreeVo> queryDatabaseList(DbQuery query) {
        ToolDatasource ds = getDsById(query) ;
        List<DataBase> dataBases = queryDb(ds);
        List<ElTreeVo> list = new ArrayList<>(dataBases.size()) ;
        for (DataBase dataBase : dataBases) {
            ElTreeVo vo = new ElTreeVo(ds.getDsId().toString() , dataBase.getDataBaseName() ,"DB" , false ) ;
            list.add(vo) ;
        }
        return list;
    }

    @Override
    public List<ElTreeVo> queryTableList(DbQuery query) {
        ToolDatasource ds = getDsById(query) ;
        String sql = "SELECT * FROM information_schema.tables  WHERE table_schema = #{query.dataBaseName}" ;
        ITToolReturnType returnType = ITToolReturnType.create(List.class, new Type[]{Tables.class});
        Map<String,DbQuery> params = new HashMap<>() ;
        params.put("query",query) ;
        List<Tables> tables = MysqlDbUtil.query(sql, ds, returnType, params);
        List<ElTreeVo> list = new ArrayList<>(tables.size()) ;
        for (Tables table : tables) {
            ElTreeVo vo = new ElTreeVo(ds.getDsId().toString() , table.getTableName() ,"TB" , true ) ;
            list.add(vo) ;
        }
        return list;
    }

    @Override
    public List<TablesColumn> queryColumnList(DbQuery query) {
        ToolDatasource ds = getDsById(query) ;
        DSql dSql = new DSql("SELECT  *   FROM information_schema.columns") ;
        dSql.eq("table_schema" , ds.getDataBaseName())
                .eq("table_name",query.getTableName()) ;
        ITToolReturnType returnType = ITToolReturnType.create(List.class, new Type[]{TablesColumn.class});
        Map<String,DbQuery> params = new HashMap<>() ;
        params.put("query",query) ;
        List<TablesColumn> columns = MysqlDbUtil.query(dSql.getSql(), ds, returnType, dSql.getParams());
        return columns;
    }

    @Override
    public IPage<ToolDatasourceVo> listByPage(RequestPage<ToolDatasource> page) {
        RequestPage<ToolDatasourceVo> toolPage = toolDatasourceMapper.listByPageVo(page);
        return toolPage;
    }

    @Override
    public Tables getTable(DbQuery query) {
        ToolDatasource ds = getDsById(query) ;
        DataSourceChange.switchDatasource(ds.getDsName() ,()->{
            return null ;
        }) ;
        DSql dSql = new DSql("SELECT * FROM information_schema.tables");
        dSql.eq("table_schema" , ds.getDataBaseName())
                .eq("table_name",query.getTableName());
        ITToolReturnType returnType = ITToolReturnType.create(Tables.class, new Type[]{Tables.class});
        return MysqlDbUtil.query(dSql.getSql() , ds , returnType  ,dSql.getParams());
    }

    @Override
    public ToolDatasource getById(Long id) {
        ToolDatasource ds = toolDatasourceMapper.selectById(id);
        String password = ds.getPassword();
        String decodePwd = EncryptUtil.getInstance().DESdecode(password, ds.getUsername());
        ds.setPassword(decodePwd);
        return ds ;
    }


    private List<DataBase> queryDb(ToolDatasource ds){
        String sql = "SELECT * FROM information_schema.schemata where schema_name = #{dbName}" ;
        Map<String,String> params = ParamKV.buildKV("dbName",ds.getDataBaseName());
        ITToolReturnType returnType = ITToolReturnType.create(List.class, new Type[]{DataBase.class});
        return MysqlDbUtil.query(sql , ds , returnType  ,params);
    }
    private List<Tables> queryTables(ToolDatasource ds){
        String sql = "SELECT * FROM information_schema.tables" ;
        ITToolReturnType returnType = ITToolReturnType.create(List.class, new Type[]{Tables.class});
        return MysqlDbUtil.query(sql , ds , returnType  ,9);
    }

    private List<TablesColumn> queryTablesColumns(ToolDatasource ds){
        String sql = "SELECT  * FROM information_schema.columns" ;
        ITToolReturnType returnType = ITToolReturnType.create(List.class, new Type[]{TablesColumn.class});
        return MysqlDbUtil.query(sql , ds , returnType  ,null);
    }
}
